﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net.Sockets;
using System.ServiceModel;

namespace cs2335lab5
{
    namespace Client
    {
        /// <summary>
        /// Interaction logic for LoginForm.xaml
        /// </summary>
        public partial class LoginForm : Window
        {
            /// <summary>
            /// This is basically a shortcut to reference the user data in the App class
            /// </summary>
            private Data.User user 
            {
                get
                {
                    return App.Instance().User;
                }
                set
                {
                    App.Instance().User = value;
                }
            }

            /// <summary>
            /// Accessor to determine if we're connected
            /// </summary>
            private bool connected
            {
                get
                {
                    try
                    {
                        return App.Instance().Proxy.Connected();
                    }
                    catch (Exception)
                    {
                        return false;
                    }
                }
            }

            /// <summary>
            /// Anything placed in this string will immediately be set to the GUI
            /// </summary>
            public string StatusString 
            {
                get { return (string)this.statusLabel.Content; }
                set { this.statusLabel.Content = value; } 
            }

            /// <summary>
            /// Public constructor: we reset GUI components, then set up data binding
            /// </summary>
            public LoginForm()
            {
                InitializeComponent();

                Reset();

                layoutRoot.DataContext = user;
            }

            /// <summary>
            /// Connect/Disconnect button handler
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void Connect_Click(object sender, RoutedEventArgs e)
            {
                // if we're connecting, try to connect
                if (!user.isConnected)
                {
                    // TODO: connect
                    App.Instance().Connect(serverTextBox.Text, portTextBox.Text);

                    if (connected)
                    {
                        // success
                        user.isConnected = true;
                        StatusString = "Successfully connected!";
                    }
                    else
                    {
                        // failure
                        user.isConnected = false;
                        StatusString = "Cannot connect :(";
                    }
                }
                else
                {
                    App.Instance().Disconnect();
                    user.isConnected = false;
                    StatusString = "Disconnected";
                }

                if (user.isConnected)
                {
                    // we successfully connected
                    // change this to a disconnected button
                    connectButton.Content = "Disconnect";

                    // enable the register and logon buttons
                    registerButton.IsEnabled = true;
                    loginButton.IsEnabled = true;

                    // disable the host and port boxes
                    serverTextBox.IsEnabled = false;
                    portTextBox.IsEnabled = false;
                }
                else
                {
                    // we either were unable to connect
                    // or just disconnected
                    connectButton.Content = "Connect";

                    // disable the register and logon buttons
                    registerButton.IsEnabled = false;
                    loginButton.IsEnabled = false;

                    // enable the host and port boxes
                    serverTextBox.IsEnabled = true;
                    portTextBox.IsEnabled = true;
                }
            }

            private void Register_Click(object sender, RoutedEventArgs e)
            {
                // check if we're connected
                if (!connected)
                {
                    // the user shouldn't be able to get here. we need
                    // to fix some UI elements to get back to a correct state
                    user.isConnected = false;
                    connectButton.Content = "Connect";
                    registerButton.IsEnabled = false;
                    loginButton.IsEnabled = false;
                    // enable the host and port boxes
                    serverTextBox.IsEnabled = true;
                    portTextBox.IsEnabled = true;

                    StatusString = "Disconnected from server!";
                    return;
                }

                // get form data
                user.ID = idTextBox.Text;
                user.Password = passwordTextBox.Password;
                user.Name = nameTextBox.Text;
                user.Email = emailTextBox.Text;
                // clear the status string
                StatusString = "";

                //idTextBox
                if (user.ID == null || user.ID.CompareTo("") == 0)
                {
                    StatusString = "Please enter a username";
                    idTextBox.Focus();
                }
                else if (user.Password == null || user.Password.CompareTo("") == 0)
                {
                    StatusString = "Please enter a password";
                    passwordTextBox.Focus();
                }
                else if (user.Name == null || user.Name.CompareTo("") == 0)
                {
                    StatusString = "Please enter your name";
                    registrationExpander.IsExpanded = true;
                    nameTextBox.Focus();
                }
                else if (user.Email == null && user.Email.CompareTo("") == 0)
                {
                    StatusString = "Please enter your email address";
                    registrationExpander.IsExpanded = true;
                    emailTextBox.Focus();
                }
                else if (!isEmailRegex(user.Email))
                {
                    StatusString = "Your email address is not valid";
                    registrationExpander.IsExpanded = true;
                    emailTextBox.Focus();
                }
                /*else if (!isEmailSmtp(CurrentUser.Email))
                {
                    // if we want to get really fancy we can do an smpt check
                    StatusString = "Cannot connect to email server. Use a different address.";
                 *  registrationExpander.IsExpanded = true;
                    emailTextBox.Focus();
                }*/

                // if we have an error message, return
                // (message is automatically placed via StatusString.Set()
                if (StatusString.CompareTo("") != 0)
                {
                    return;
                }

                // ask the server if this username is taken
                if (App.Instance().Proxy.Register(user) != null)
                {
                    // user is registered
                    StatusString = "Registration successful!";
                }
                else
                {
                    // username is taken
                    StatusString = "Username taken. Please choose another.";
                }
            }

            private void Login_Click(object sender, RoutedEventArgs e)
            {
                // check if we're connected
                if (!user.isConnected)
                {
                    StatusString = "Please connect!";
                    return;
                }

                // get form data
                user.ID = idTextBox.Text;
                user.Password = passwordTextBox.Password;
                user.Name = nameTextBox.Text;
                user.Email = emailTextBox.Text;
                // clear the status string
                StatusString = "";

                //idTextBox
                if (user.ID == null || user.ID.CompareTo("") == 0)
                {
                    StatusString = "Please enter a username";
                    idTextBox.Focus();
                }
                else if (user.Password == null || user.Password.CompareTo("") == 0)
                {
                    StatusString = "Please enter a password";
                    passwordTextBox.Focus();
                }

                // if we have an error message, return
                // (message is automatically placed via StatusString.Set()
                if (StatusString.CompareTo("") != 0)
                {
                    return;
                }

                // TODO: ask the server if this username/password is valid
                
                Data.User result = App.Instance().Proxy.Authenticate(user);
                if (result != null)
                {
                    // username/password are valid
                    StatusString = "";

                    // set user details
                    App.Instance().User = result;

                    // TODO: log in user by hiding this window and showing an
                    App.Instance().ShowClient();
                }
                else
                {
                    // bad username or password
                    StatusString = "Login failed: bad username or password";
                }
            }

            /// <summary>
            /// Tests if a string matches the pattern inherent in email addresses
            /// </summary>
            /// <param name="inputEmail">string to check</param>
            /// <returns>whether the string matches the regex</returns>
            public static bool isEmailRegex(string inputEmail)
            {
                string strRegex = @"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}" +
                      @"\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\" +
                      @".)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";
                Regex re = new Regex(strRegex);
                if (re.IsMatch(inputEmail))
                    return (true);
                else
                    return (false);
            }

            /// <summary>
            /// Method that attempts to verify the validity of an email domain
            /// Wasn't working when I tried it earlier.
            /// </summary>
            /// <param name="inputEmail">email address to check</param>
            /// <returns>whether connection to server was successful</returns>
            public static bool isEmailSmtp(string inputEmail)
            {
                string[] host = (inputEmail.Split('@'));
                string hostname = host[1];

                IPHostEntry IPhst = Dns.GetHostEntry(hostname);
                IPEndPoint endPt = new IPEndPoint(IPhst.AddressList[0], 25);
                Socket s = new Socket(endPt.AddressFamily,
                        SocketType.Stream, ProtocolType.Tcp);
                try
                {
                    s.Connect(endPt);
                }
                catch (Exception)
                {
                    return false;
                }
                finally
                {
                    s.Close();
                }

                return true;
            }

            /// <summary>
            /// resets the form to its original state
            /// </summary>
            internal void Reset()
            {
                // reset data
                user = new Data.User();
                StatusString = "";
                passwordTextBox.Password = "";

                // disconnect if we're connected
                App.Instance().Disconnect();

                // reset button states
                connectButton.Content = "Connect";
                registerButton.IsEnabled = false;
                loginButton.IsEnabled = false;
            }
        }
    }
}